<?php

namespace app\admin\service;

use app\admin\model\Menu as Model;
use app\lib\exception\Menu as MenuException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Session;

class Menu
{


    /**
     * 递归获取分类配置 树形显示 一维数组
     * @param array $data data
     * @param int $parent_id pid
     * @param int $level level
     * @return arr             result
     */
    private function getTree($data, $parent_id = 0, $level = 0): array
    {
        static $tree = array();
        foreach ($data as $key => $value) {
            if ($value['parent_id'] == $parent_id) {
                $label = str_repeat('——', $level * 2) . $value['title'];
                $tree[] = [
                    'label' => $label,
                    'value' => $value['id'],
                ];
                unset($data[$key]);
                $this->getTree($data, $value['id'], $level + 1);
            }
        }
        return $tree;
    }

    /**
     * 获取无限极分类数组（直接是树形结构的数组）
     * @param $data
     * @return array
     */
    private function getTreeArr($data): array
    {
        //构造数据
        $items = array();
        //以分类的id为索引
        foreach ($data as $key => $value) {
            $items[$value['id']] = $value;
        }
        //第二部 遍历数据 生成树状结构
        $tree = array();
        foreach ($items as $key => $value) {
            if ($value['parent_id'] !== 0) { //不是顶级分类
                //把当前循环的value放入父节点下面
                $items[$value['parent_id']]['children'][] = &$items[$key];
                //引用传值  当items更改时，tree里面的items也会更改
            } else {
                $tree[] = &$items[$key];
            }
        }
        return $tree;
    }

    /**
     * 递归返回可使用格式的权限节点
     * @param $data
     * @return array
     */
    private function executeTreeArr($data): array
    {
        $res = array();
        foreach ($data as $key => $value) {
            $arr = [
                'id' => $value['id'],
                'label' => $value['title'],
            ];
            if (!empty($value['children'])) {
                $arr['children'] = $this->executeTreeArr($value['children']);
            }
            $res[$key] = $arr;
        }
        return $res;
    }


    /**
     * 判断请求是否有权限
     * @param $path
     * @return true
     * @throws MenuException
     */
    static function verifyMenu($path, $roleList): bool
    {
        $res = (new Model)->where([
            'name' => $path['action'],
            'controller' => $path['controller'],
            'http_name' => $path['module'],
        ])->findOrEmpty();
        if ($res->isEmpty()) {
            throw new MenuException();
        }

        Session::set('menu_title', $res['title']);
        $ids = Session::get('admin_id');
        if ($ids == 1) return true;
        $roleLists = self::getRoleList($roleList);
        $rules = [];
        foreach ($roleLists as $k => $v) {
            $rules[] = $v['http_name'] . '/' . $v['controller'] . '/' . strtolower($v['name']);
        }
        $paths = $path['module'] . '/' . $path['controller'] . '/' . strtolower($path['action']);

        if (in_array($paths, $rules)) {
            return true;
        } else {
            throw new MenuException();
        }
    }

    static function getRoleList($roleList): array
    {
        return (new Model)->whereIn('id', $roleList)->where('hidden', 1)->select()->toArray();
    }

    static function getRoleListHidden($ids): array
    {
        $where = [];
        $where[] = ['id', 'in', $ids];
        $where[] = ['hidden', '=', 0];
        $where[] = ['id', '<>', 1];
        return (new Model)->where($where)->select()->toArray();
    }

    static function getLists($field = '*'): array
    {
        $where = [];
        return (new Model)->where($where)->field($field)->select()->toArray();
    }

    /**
     * @param string $field
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    static function menuAllList(string $field = '*'): array
    {
        $res = (new Model)->field($field)->select()->toArray();
        $res = (new Menu)->getTreeArr($res);
        $data = (new Menu)->executeTreeArr($res);
        return $data;
    }

    /**
     * @param $param
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    static function menuList($param): array
    {
        $where = [];
        if (!empty($param['id'])) {
            $where[] = ['id', '<>', $param['id']];
        }
        $field = '*';
        $find = (new Model)->where($where)->field($field)->select()->toArray();
        $find_cloumn = array_column($find, 'title', 'id');
//        var_dump($find_cloumn);exit();
        foreach ($find as &$item) {
            if ($item['parent_id'] != 0 && array_key_exists($item['parent_id'], $find_cloumn)) {
                $item['parent_Name'] = $find_cloumn[$item['parent_id']] . '-' . $item['parent_id'];
            } else {
                $item['parent_Name'] = '';
            }
            $item['value'] = $item['id'];
            $item['label'] = $item['title'];
        }
        $data = (new Menu)->getTreeArr($find);
        return $data;
    }

    /**
     * @param $param
     * @return array
     * @throws MenuException
     */
    static function menuDetail($param): array
    {
        if (empty($param)) throw new MenuException();
        $where = [
            'id' => $param['id'],
        ];
        $find = (new Model)->where($where)->findOrEmpty();
        if ($find->isEmpty()) throw new MenuException();
        return $find->toArray();
    }

    /**
     * @param $param
     * @return array
     * @throws MenuException
     */
    protected static function getArr($param, $type = 'add'): array
    {
        if (empty($param)) throw new MenuException();
        if ($type == 'add') {
            if (Model::getByTitle($param['title'])) {
                throw new MenuException(['msg' => '菜单名称已存在']);
            }
            if (Model::getByPath($param['path'])) {
                throw new MenuException(['msg' => '路由地址已存在']);
            }
            if (Model::getByName($param['name'])) {
                throw new MenuException(['msg' => '路由名称已存在']);
            }
            if (Model::getByComponent($param['component'])) {
                throw new MenuException(['msg' => '映射组件名称已存在']);
            }
        } else {
            $find = (new Model)->where([
                ['title', '=', $param['title']],
                ['id', '<>', $param['id']]
            ])->findOrEmpty();
            if (!$find->isEmpty()) {
                throw new MenuException(['msg' => '菜单名称已存在']);
            }
            $find = (new Model)->where([
                ['path', '=', $param['path']],
                ['id', '<>', $param['id']]
            ])->findOrEmpty();
            if (!$find->isEmpty()) {
                throw new MenuException(['msg' => '路由地址已存在']);
            }
            $find = (new Model)->where([
                ['name', '=', $param['name']],
                ['id', '<>', $param['id']]
            ])->findOrEmpty();
            if (!$find->isEmpty()) {
                throw new MenuException(['msg' => '路由名称已存在']);
            }
            $find = (new Model)->where([
                ['component', '=', $param['component']],
                ['id', '<>', $param['id']]
            ])->findOrEmpty();
            if (!$find->isEmpty()) {
                throw new MenuException(['msg' => '映射组件名称已存在']);
            }
        }

        $data = [];
        $data['title'] = $param['title'];
        $data['path'] = $param['path'];
        $data['name'] = $param['name'];
        $data['component'] = $param['component'];
        $data['redirect'] = $param['redirect'];
        $data['hidden'] = $param['hidden'];
        $data['icon'] = $param['icon'];
        $data['parent_id'] = $param['parent_id'];
        $data['http_name'] = $param['http_name'];
        $data['controller'] = $param['controller'];
        return $data;
    }

    /**
     * @param $param
     * @return array|bool
     * @throws MenuException
     */
    static function menuAdd($param): bool
    {
        $data = self::getArr($param);
//        var_dump($data);exit();
        $res = (new Model)->save($data);
        if ($res !== false) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @param $param
     * @return array|bool
     * @throws MenuException
     */
    static function menuEdit($param): bool
    {
        $data = self::getArr($param, 'edit');
        $res = (new Model)->Update($data, ['id' => $param['id']]);
        if ($res !== false) {
            return true;
        } else {
            return false;
        }
    }

    static function menuDelete($ids): bool
    {
        if (empty($ids)) throw new MenuException();
        $find = (new Model)::find($ids);
        $res = $find->delete();
//        $find = (new model)::onlyTrashed()->find($ids);
//        $res = $find->restore();
        if ($res !== false) {
            return true;
        } else {
            return false;
        }
    }
}